// nettest.cc 
//	Test out message delivery between two "Nachos" machines,
//	using the Post Office to coordinate delivery.
//
//	Two caveats:
//	  1. Two copies of Nachos must be running, with machine ID's 0 and 1:
//		./nachos -m 0 -o 1 &
//		./nachos -m 1 -o 0 &
//
//	  2. You need an implementation of condition variables,
//	     which is *not* provided as part of the baseline threads 
//	     implementation.  The Post Office won't work without
//	     a correct implementation of condition variables.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "netsynch.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include <string>

// Test out message delivery, by doing the following:
//	1. send a message to the machine with ID "farAddr", at mail box #0
//	2. wait for the other machine's message to arrive (in our mailbox #0)
//	3. send an acknowledgment for the other machine's message
//	4. wait for an acknowledgement from the other machine to our 
//	    original message

void
MailTest(int farAddr)
{
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;

    char *ack = "Got it";
    char *data = "Hello there!";
    char buffer[MaxMailSize];

    // construct packet, mail header for original message
    // To: destination machine, mailbox 0
    // From: our machine, reply to: mailbox 1
    outPktHdr.to = farAddr;		
    outMailHdr.to = 0;
    outMailHdr.from = 1;
    outMailHdr.length = strlen(data) + 1;

    // Send the first message
    bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the first message from the other machine
    postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Send acknowledgement to the other machine (using "reply to" mailbox
    // in the message that just arrived
    outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(ack) + 1;
    success = postOffice->Send(outPktHdr, outMailHdr, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the ack from the other machine to the first message we sent.
    postOffice->Receive(1, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Then we're done!
    interrupt->Halt();
}
/***************************************************************************************/
/*Function to decode the message*/
int msgParsers2(char *msg){
  char* msgCopy = new char(*msg);
  char* delimiter = new char(' ');
  char* firstToken = strtok(msgCopy, delimiter); // get the first token, an integer represented by ascii characters
  return atoi(firstToken); // convert that first token to an int value and return it
}


int msgParsers(char msg[]){
  char* msgCopy = new char(sizeof(msg));
  char* delimiter = new char(' ');
  char* firstToken = strtok(msg, delimiter); // get the first token, an integer represented by ascii characters
  return atoi(firstToken); // convert that first token to an int value and return it
}

/***************************************************************************************/
/*Function to send the message from the server ******/
bool sendMsg(PacketHeader inPktHdr, MailHeader inMailHdr,char* data){

  PacketHeader outPktHdr;
  MailHeader outMailHdr;
 
  
  
  outPktHdr.to = inPktHdr.from;
  outMailHdr.to = inMailHdr.from;
  outMailHdr.from = 0;  
  outMailHdr.length = strlen(data) + 1;

  bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

  return success;
}



//**************************************************************************************/
//This is where the server gonna be!
void Server(int t){
  PacketHeader outPktHdr, inPktHdr;
  MailHeader outMailHdr, inMailHdr;


  char *data = "Hello there!";
  char *ack = new char[MaxMailSize];
  char buffer[MaxMailSize];
  NetSynch *ns = new NetSynch();
  

  int requestMsg ;
  bool success = false;

  cout <<"YEAH! Server is up!\n";

  while(true){

    // Wait for the first message from the other machine
    postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    // requestMsg = msgParsers(buffer);
    fflush(stdout);

  
    //Switch function to detect what type of request the client is sending to the server!
    //0 = Create Lock
    //1 = Acquire
    //2 = Release
    //3 = Destroy Lock
    //4 = Create Condtion
    //5 = Wait
    //6 = Signal
    //7 = Broadcast
    //8 = Destroy Condition
    
   
//     char *msgCopy = new char(*buffer);
//     char* delimiter = new char (' ');
    int count = 0;

    char* token;
    int lockNum = -1;
    int condNum = -1;
    int temp;
    char *fake = new char[sizeof(buffer)];

    for(token = strtok(buffer," ");token!=NULL;token = strtok(NULL," ")){
      fake = token;
      if (count == 0 )
	requestMsg = atoi(fake);
      else if(count == 2)
	lockNum = atoi(fake);
      else if(count == 4)
	condNum = atoi(fake);
      count++;
    }


    switch(requestMsg){
      /****************************************/
    case 0:   
      cout<<"Server: receive Create Lock Msg\n";
      temp =  ns->createLock(lockNum);
      cout << "The position returned to user in lockArray is " << temp << endl;
      sprintf(ack,"%d LockACK",temp);

      //send back the message to ack that msg have been created
      success = sendMsg(inPktHdr, inMailHdr, ack);
      if ( !success ) {
	printf("Server, CreateLock: The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	interrupt->Halt();
      }
      else{
	cout<<"SENT ACK Create Lock\n";
      }
      break;

      /*****************************************/
    case 1:
      cout<<"Server: Receive Acquire Lock Msg\n";
      temp =  ns->Acquire(lockNum,inPktHdr,inMailHdr);
     
      if(temp == 0){
	sprintf(ack,"%d AcquireACK",temp);
	
	//send back the message to ack that msg have been created
	success = sendMsg(inPktHdr, inMailHdr, ack);
	if ( !success ) {
	  printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	  interrupt->Halt();
	}
	else{
	  cout<<"Server: SENT ACK Acquire Lock\n";
	}
      }
      break;

      /*******************************************/
    case 2:
      cout<<"Server: Receive Release Lock Msg\n";
      ns->Release(lockNum,inPktHdr,inMailHdr);
 
     
      sprintf(ack," ReleaseACK");
      //send back the message to ack that that the lock has been release
      success = sendMsg(inPktHdr, inMailHdr, ack);
      if ( !success ) {
	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	interrupt->Halt();
      }
      else{
	cout<<"Server: SENT ACK Release Lock\n";
      }
      break;
      /*********************************************/

    case 3:
      cout<<"case 3\n";
      break;

      /********************************************/
    case 4:
      cout<<"Server: Receive the Create Condition Msg\n";
  
      temp= ns->createCondition(lockNum);
      sprintf(ack,"%d CreateCondACK",temp);
      cout << "The position returned to user in condArray is " << temp << endl;
      success = sendMsg(inPktHdr, inMailHdr,ack);
      if ( !success ) {
	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	interrupt->Halt();
      }
      else{
	cout<<"SENT ACK Create Condtion\n";
      }
      break;

      /*******************************************/
    case 5:
      cout<<"Server: Receive the Wait Msg\n";
      cout<<"LockNum: "<<lockNum<<endl;
      cout<<"CondNum: "<<condNum<<endl;
      ns->Wait(lockNum,condNum,inPktHdr,inMailHdr);
      break;

      /*****************************************/
    case 6:
      cout<<"Server:Receive Signal Msg\n";
      cout<<"Server: LockNum: "<<lockNum<<endl;
      cout<<"Server: CondNum: "<<condNum<<endl;
      ns->Signal(lockNum,condNum,inPktHdr);
      cout<<"Server: Done signal, now release the lock\n";
      //ns->Release(lockNum,inPktHdr,inMailHdr);
      sprintf(ack,"%d SignalACK",condNum);
      success = sendMsg(inPktHdr, inMailHdr,ack);
      if ( !success ) {
	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	interrupt->Halt();
      }
      else{
	cout<<"Server: SENT ACK Signal\n";
	}

      break;
    case 7:
      cout<<"Server:Receive Broadcast Msg\n";

      cout<<"LockNum: "<<lockNum<<endl;
      cout<<"CondNum: "<<condNum<<endl;
      ns->Broadcast(lockNum,condNum,inPktHdr);
  
      sprintf(ack,"%d BroadcastACK",condNum);
      success = sendMsg(inPktHdr, inMailHdr,ack);
      if ( !success ) {
	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	interrupt->Halt();
      }
      else{
	cout<<"Server: SENT ACK Broadcast\n";
      }
      break;
      
    default:
      cout<<"Stupid function!";
      break;

    }//end switch
  

  }
}

